<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>排序算法可视化</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 20px;
        }

        .controls {
            margin: 20px 0;
        }

        button {
            margin: 0 10px;
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
            border: 1px solid #ccc;
            border-radius: 4px;
            background-color: white;
        }

        button.active {
            background-color: #007bff;
            color: white;
            border-color: #0056b3;
        }

        button:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        .visualizer {
            margin: 20px auto;
            width: 800px;
        }

        .array-container {
            height: 300px;
            display: flex;
            align-items: flex-end;
            padding: 20px;
            background-color: #f5f5f5;
            border-radius: 8px;
        }

        .array-bar {
            flex: 1;
            margin: 0 1px;
            background-color: #007bff;
            transition: height 0.1s ease;
            position: relative;
            display: flex;
            justify-content: center;
        }

        .array-bar::after {
            content: attr(data-value);
            position: absolute;
            top: -20px;
            font-size: 12px;
            color: #333;
        }

        .speed-control {
            margin-top: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
        }
        
        #speed {
            width: 200px;
        }

        .array-bar.current {
            background-color: #dc3545;
        }

        .array-bar.comparing {
            background-color: #ffc107;
        }
    </style>
</head>
<body>
    <h1>排序算法可视化</h1>
    
    <div class="controls">
        <button onclick="setAlgorithm('bubble')" class="active" id="bubbleBtn">冒泡排序</button>
        <button onclick="setAlgorithm('quick')" id="quickBtn">快速排序</button>
        <button onclick="setAlgorithm('merge')" id="mergeBtn">归并排序</button>
        <div class="speed-control">
            <label for="speed">速度: </label>
            <input 
                type="range" 
                id="speed" 
                min="50" 
                max="1000" 
                value="300"
                oninput="updateSpeedLabel()"
            >
            <span id="speedLabel">300ms</span>
        </div>
    </div>

    <div class="visualizer">
        <div class="array-container" id="arrayContainer"></div>
        <div class="controls">
            <button onclick="generateArray()" id="generateBtn">生成新数组</button>
            <button onclick="startSort()" id="sortBtn">开始排序</button>
            <button onclick="togglePause()" id="pauseBtn" disabled>暂停</button>
            <button onclick="stopSort()" id="stopBtn" disabled>停止排序</button>
        </div>
    </div>

    <script>
        let array = [];
        let sorting = false;
        let currentAlgorithm = 'bubble';
        let stopSorting = false;
        let sortingSpeed = 300; // 默认排序速度（毫秒）
        let isPaused = false;

        // 生成随机数组
        function generateArray() {
            array = Array.from({length: 30}, () => Math.floor(Math.random() * 100) + 1);
            displayArray();
        }

        // 显示数组
        function displayArray(current = -1, comparing = -1) {
            const container = document.getElementById('arrayContainer');
            container.innerHTML = '';
            array.forEach((value, index) => {
                const bar = document.createElement('div');
                bar.className = 'array-bar';
                if (index === current) {
                    bar.classList.add('current');
                }
                if (index === comparing) {
                    bar.classList.add('comparing');
                }
                bar.style.height = `${value * 3}px`;
                bar.setAttribute('data-value', value);
                container.appendChild(bar);
            });
        }

        // 设置当前算法
        function setAlgorithm(algorithm) {
            currentAlgorithm = algorithm;
            document.querySelectorAll('.controls button').forEach(btn => {
                btn.classList.remove('active');
            });
            document.getElementById(`${algorithm}Btn`).classList.add('active');
        }

        // 更新速度标签
        function updateSpeedLabel() {
            const speed = document.getElementById('speed').value;
            sortingSpeed = parseInt(speed);
            document.getElementById('speedLabel').textContent = speed + 'ms';
        }

        // 修改 sleep 函数使用动态速度
        function sleep(ms) {
            return new Promise(resolve => setTimeout(resolve, sortingSpeed));
        }

        // 暂停/继续排序
        function togglePause() {
            isPaused = !isPaused;
            document.getElementById('pauseBtn').textContent = isPaused ? '继续' : '暂停';
        }

        // 等待继续
        async function waitIfPaused() {
            while (isPaused && !stopSorting) {
                await sleep();
            }
        }

        // 冒泡排序
        async function bubbleSort() {
            const n = array.length;
            for (let i = 0; i < n - 1; i++) {
                for (let j = 0; j < n - i - 1; j++) {
                    await waitIfPaused();
                    if (stopSorting) return;
                    
                    if (array[j] > array[j + 1]) {
                        [array[j], array[j + 1]] = [array[j + 1], array[j]];
                        displayArray(j + 1, j);
                        await sleep();
                    }
                }
            }
        }

        // 快速排序
        async function quickSort(start = 0, end = array.length - 1) {
            if (start >= end || stopSorting) return;
            await waitIfPaused();
            
            const pivot = array[end];
            let i = start - 1;
            
            for (let j = start; j < end; j++) {
                if (stopSorting) return;
                await waitIfPaused();
                if (array[j] < pivot) {
                    i++;
                    [array[i], array[j]] = [array[j], array[i]];
                    displayArray(j, i);
                    await sleep();
                }
            }
            
            [array[i + 1], array[end]] = [array[end], array[i + 1]];
            displayArray(i + 1, end);
            await sleep();
            
            const pi = i + 1;
            await quickSort(start, pi - 1);
            await quickSort(pi + 1, end);
        }
        
        // 归并排序
        async function mergeSort(start = 0, end = array.length - 1) {
            if (start >= end || stopSorting) return;
            
            const mid = Math.floor((start + end) / 2);
            await mergeSort(start, mid);
            await mergeSort(mid + 1, end);
            await merge(start, mid, end);
        }
        
        // 归并操作
        async function merge(start, mid, end) {
            if (stopSorting) return;
            await waitIfPaused();
            
            const left = array.slice(start, mid + 1);
            const right = array.slice(mid + 1, end + 1);
            let i = 0, j = 0, k = start;
            
            while (i < left.length && j < right.length) {
                if (stopSorting) return;
                await waitIfPaused();
                if (left[i] <= right[j]) {
                    array[k] = left[i];
                    i++;
                } else {
                    array[k] = right[j];
                    j++;
                }
                displayArray(k);
                k++;
                await sleep();
            }
            
            while (i < left.length) {
                if (stopSorting) return;
                array[k] = left[i];
                i++;
                k++;
                displayArray(k);
                await sleep();
            }
            
            while (j < right.length) {
                if (stopSorting) return;
                array[k] = right[j];
                j++;
                k++;
                displayArray(k);
                await sleep();
            }
        }
        
        // 停止排序
        function stopSort() {
            stopSorting = true;
            isPaused = false;
            document.getElementById('generateBtn').disabled = false;
            document.getElementById('sortBtn').disabled = false;
            document.getElementById('stopBtn').disabled = true;
            document.getElementById('pauseBtn').disabled = true;
        }

        // 开始排序
        async function startSort() {
            if (sorting) return;
            sorting = true;
            stopSorting = false;
            isPaused = false;
            document.getElementById('generateBtn').disabled = true;
            document.getElementById('sortBtn').disabled = true;
            document.getElementById('stopBtn').disabled = false;
            document.getElementById('pauseBtn').disabled = false;
            document.getElementById('pauseBtn').textContent = '暂停';

            switch (currentAlgorithm) {
                case 'bubble':
                    await bubbleSort();
                    break;
                case 'quick':
                    await quickSort();
                    break;
                case 'merge':
                    await mergeSort();
                    break;
            }

            sorting = false;
            if (!stopSorting) {
                document.getElementById('generateBtn').disabled = false;
                document.getElementById('sortBtn').disabled = false;
                document.getElementById('stopBtn').disabled = true;
                document.getElementById('pauseBtn').disabled = true;
            }
        }

        // 初始化
        generateArray();
    </script>
</body>
</html> 